/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package se.sll.itintegration.catalogue.camel.processor;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import lombok.extern.slf4j.Slf4j;

import org.apache.camel.Body;
import org.apache.camel.Exchange;
import org.apache.camel.Property;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;

import se.sll.itintegration.catalogue.gui.data.OfferView;
import se.sll.itintegration.catalogue.gui.service.HsaCache;
import se.sll.service.catalogue.common.data.UnitId;
import se.sll.service.catalogue.common.data.UnitList;
import se.sll.service.catalogue.common.rest.model.Product;
import se.sll.service.catalogue.common.rest.model.ProductReference;
import se.sll.service.catalogue.common.rest.model.Unit;
import se.sll.service.catalogue.common.rest.model.user.CareUnitReference;
import se.sll.service.catalogue.common.rest.model.user.User;
import se.sll.service.catalogue.common.rest.response.HsaData;

/**
 *
 * @author khaleddaham
 */
@Slf4j
public class OfferProcessor {

    private static final OfferProcessor INSTANCE = new OfferProcessor();
    private final HsaCache hsaCache;
    private ObjectMapper mapper = null;

    private OfferProcessor() {
        try {
            InitialContext context = new InitialContext();
            hsaCache = (HsaCache) context.lookup("java:module/GUI-HSACache");
        } catch (NamingException ex) {
            throw new RuntimeException(ex);
        }
        mapper = new ObjectMapper();
    }

    /**
     *
     * @param exchange
     */
    public void createView(Exchange exchange) {
        exchange.setProperty("view", new OfferView());
    }

    /**
     *
     * @param exchange
     * @throws JsonParseException
     * @throws JsonMappingException
     * @throws IOException
     */
    public void offerResponseJSON(Exchange exchange) throws JsonParseException, JsonMappingException, IOException {
        exchange.getIn().setBody(convertToJsonToUnit(exchange));
    }

    /**
     *
     * @param exchange
     * @param grouped
     * @param view
     * @throws JsonParseException
     * @throws JsonMappingException
     * @throws IOException
     */
    public void mergeToOfferView(Exchange exchange, @Body List<Exchange> grouped, @Property("view") OfferView view) throws IOException, JsonMappingException, IOException {
        @SuppressWarnings("unchecked")
        List<Unit> offer = (List<Unit>) grouped.get(0).getIn().getBody();

        @SuppressWarnings("unchecked")
        Map<String, Product> productMap = (Map<String, Product>) grouped.get(1).getIn().getBody();

        @SuppressWarnings("unchecked")
        List<User> users = (List<User>) grouped.get(2).getIn().getBody();

        try {
            view.setOffer(offer);
            for (Unit unit : offer) {
                HsaData hsaData
                        = hsaCache.getHsa(unit.getUnitId());
                if (hsaData != null) {
                    unit.setRelativeDistinguishedName(hsaData.getRelativeDistinguishedName());
                }
                for (ProductReference pr
                        : unit.getProductReferences()) {
                    log.info(pr.toString());
                    log.info(pr.getProduct().toString());
                    Product p = productMap.get(pr.getProduct().getName());
                    if (p != null) {
                        pr.getProduct().setDisplayName(p.getDisplayName());
                        pr.getProduct().setDescription(p.getDescription());
                    }
                }
            }
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }

        try {
            view.setProduct(productMap);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }

        try {
            Map<String, User> userMap = new HashMap<>();
            for (User user : users) {
                if (user.getHsaId() != null) {
                    userMap.put(user.getHsaId(), user);
                }
            }
            view.setUser(userMap);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }

        exchange.getIn()
                .setBody(view);
    }

    public void mergeToOneOfferView(Exchange exchange, @Body List<Exchange> grouped, @Property("view") OfferView view) throws IOException, JsonMappingException, IOException {
        @SuppressWarnings("unchecked")
        List<Unit> offer = (List<Unit>) grouped.get(0).getIn().getBody();

        @SuppressWarnings("unchecked")
        Map<String, Product> productMap = (Map<String, Product>) grouped.get(1).getIn().getBody();

        try {
            view.setOffer(offer);
            for (Unit unit : offer) {
                HsaData hsaData
                        = hsaCache.getHsa(unit.getUnitId());
                if (hsaData != null) {
                    unit.setRelativeDistinguishedName(hsaData.getRelativeDistinguishedName());
                }
                for (ProductReference pr
                        : unit.getProductReferences()) {
                    Product p = productMap.get(pr.getProduct().getName());
                    pr.getProduct().setDisplayName(p.getDisplayName());
                    pr.getProduct().setDescription(p.getDescription());
                }
            }
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }
        exchange.getIn().setBody(view);
    }

    /**
     *
     * @param exchange
     * @return
     * @throws IOException
     */
    private List<Unit> convertToJsonToUnit(Exchange exchange) throws IOException {
        mapper = new ObjectMapper();
                mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        String data = exchange.getIn().getBody(String.class
        );
        return mapper.readValue(data,
                new TypeReference<List<Unit>>() {
                }
        );
    }

    /**
     * Converts a list of Units to a list of UnitReferences, adding displayName
     * from the HSA cache.
     *
     * @param exchange
     * @param units
     */
    public void unitsToUnitReferences(Exchange exchange, @Body List<Unit> units) {
        List<CareUnitReference> unitReferences = new ArrayList<>(units.size());
        for (Unit unit : units) {
            CareUnitReference unitReference = new CareUnitReference();
            String unitId = unit.getUnitId();
            unitReference.setHsaId(unitId);
            HsaData hsaData = hsaCache.getHsa(unitId);
            if (hsaData != null) {
                unitReference.setDisplayName(hsaData.getRelativeDistinguishedName());
            }
            unitReferences.add(unitReference);
        }
        exchange.getIn().setBody(unitReferences);
    }

    /**
     *
     * @param exchange
     */
    public void listToOfferModel(Exchange exchange) {
        UnitList l = new UnitList();
        List<UnitId> lu = new ArrayList<>();
        List<?> hsaIdList = exchange.getIn().getBody(List.class
        );
        for (Object a : hsaIdList) {
            UnitId u = new UnitId(a.toString());
            lu.add(u);
        }

        l.setUnits(lu);

        exchange.getIn()
                .setBody(l);
    }

    public static OfferProcessor getInstance() {
        return INSTANCE;
    }
}
